import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;


public class AndroidFile extends File
{
	private String tag;
	private boolean decompiled=false;
	private boolean compiled=false;
	private AndroidFileFilter filter;
	private static final long serialVersionUID = 1L;
public AndroidFile(File selectedFile) {
	super(selectedFile.getAbsolutePath());
	init(params.oTag);
}
/**
 * 
 * @param pathname - file path (relative or full)
 */
	public AndroidFile(String pathname)
	{
		super(pathname);
		init(params.oTag);
	}

	/**
	 * 
	 * @param pathname - file path (relevnt or full)
	 * @param frameworkTag - frameworktag this file should use)
	 */
	public AndroidFile(String pathname,String frameworkTag)
	{
		super(pathname);
		init(frameworkTag);
	}
	
		
	/**
	 * delete decompild folder and temp compiled file
	 * 
	 * @return
	 */
	public void clear()
	{
		Log.debug("Clear: "+getAbsolutePath());
		deleteCompiled();
		deleteDecompiled();
		return;
	}

	public String compile()
	{
		Log.debug("Compiling: "+getAbsolutePath());
		if (!isDecompiled())
		{
			Log.error(getAbsolutePath()+" is not decompiled");
			return null;
		}
		File temp=new File(getDecompiledPath());
		if (!temp.exists())
		{			
			Log.error("Decompiled directory not found");
			return null;
		}
		Log.debug("compiling file: "+getName());
		String out=getCompiledPath();
		ArrayList<String> cmd=new ArrayList<String>(Arrays.asList(params.apktool));
		cmd.add("b");
		cmd.add(temp.getAbsolutePath());
		cmd.add(out);
		if (HelpFunctions.run_command(cmd, false, false, params.libDir))
		{
			deleteDecompiled();
			compiled=true;
			return out;
		}
		else
		{
			Log.error("Compile failed");
			return null;
		}
	}

	/**
	 * Add a given file to the package.<BR>
	 * Source file will remain on disk and is not deleted
	 * @param add
	 * @return
	 */
	public boolean compress(String add)
	{
		return compress(add,false);
	}
	
	/**
	 * 
	 * @param add - path to file which will be added to archive
	 * @param deletefile - true if you want to delete that file from disk after adding it
	 * @return
	 */
	public boolean compress(String add,boolean deletefile)
	{
		
		boolean ret;
		ret=HelpFunctions.addToZip(getAbsolutePath(),add);
		if (ret && deletefile)
		{
			File temp=new File(add);
			ret=temp.delete();
			if (ret)
				Log.debug(add + " was succsefully deleted");
			else
				Log.error(add + " could not be deleted");				
		}
		return ret;
	}

	public boolean decompile()
	{
		Log.debug("decompiling: "+getAbsolutePath());
		if (!isFile())
		{
			Log.error(getAbsolutePath()+" is not a valid android file");
			return false;
		}
		if (tag==null)
		{
			Log.error("No tag initialized");
			return false;
		}
		String out=getDecompiledPath();
		deleteDecompiled();
		ArrayList<String> cmd=new ArrayList<String>(Arrays.asList(params.apktool));
		cmd.add("d");
		cmd.add("-f");
		cmd.add("-t");
		cmd.add(tag);
		cmd.add(getAbsolutePath());
		cmd.add(out);
		boolean ret=HelpFunctions.run_command(cmd,false,false,params.libDir);
		if (ret)
		{
			decompiled=true;
			return true;
		}
		else
		{
			Log.error("Decompiled failed");
			return ret;
		}
	}

	public boolean deleteCompiled()
	{
		if (isCompiled())
		{
			boolean ret=new File(getCompiledPath()).delete();
			if (!ret)
			{
				Log.error("Could not delete "+getCompiledPath());
				return false;
			}
			compiled=false;
			return true;
		}
		else return false;
	}

	public boolean deleteDecompiled()
	{
		if (isDecompiled())
		{
			boolean ret=HelpFunctions.deleteDir(new File(getDecompiledPath()));
			if (!ret)
			{
				Log.error("Could not delete "+getDecompiledPath());
				return false;
			}
			decompiled=false;
			return true;
		}
		else return false;
	}
	/**
	 * extract a given file from package
	 * @param extract - file to extract
	 * @param fromCompiled - true if you want to extract from the compiled file
	 * @return
	 */
	public boolean extract(String extract,boolean fromCompiled)
	{
		String st=getAbsolutePath();
		if (fromCompiled)
		{
			if (!isCompiled())
			{
				Log.error(getName()+" was not compiled");
				return false;
			}
			st=getCompiledPath();
		}
		return HelpFunctions.extractZip(st, extract);
	}

	/**
	 * Returns the absolute path to the compiled apk
	 * @return
	 */
	public String getCompiledPath()
	{
		return getAbsolutePath()+params.compiledTag;
	}

	public String getDecompiledPath()
	{
		return getAbsolutePath()+params.decompiledTag;
	}
	private void init(String tagtouse)
	{
		tag=tagtouse;
		filter=new AndroidFileFilter();
	}

	public boolean isCompiled()
	{
		if (compiled)
			return true;
		File temp=new File(getCompiledPath());
		if (temp.exists())
			compiled=true;
		return compiled;
	}

	public boolean isDecompiled()
	{
		if (decompiled)
			return true;
		File temp=new File(getDecompiledPath());
		if (temp.exists())
			decompiled=true;
		return decompiled;
	}
	@Override
	public boolean isFile()
	{
		boolean temp=super.isFile();
		return temp && filter.accept(this);

	}

	/**
	 * replace original apk with compiled one
	 * @return
	 */
	public boolean replaceOriginalCompiled()
	{
		Log.debug("replaceOriginalCompiled: ");
		File temp=new File(getCompiledPath());
		if (!temp.exists())
		{
			Log.error("compiled file not found");
			return false;
		}
		boolean ret=delete();
		if (!ret)
		{
			Log.error("could not delete: "+getAbsolutePath());
			return false;
		}
		return temp.renameTo(getAbsoluteFile());
	}

	/**
	 * copy specified files from compiled file to original file	
	 * @param resources - String array consisting of file path inside the archive
	 * @return
	 */
	public boolean replaceResources(ArrayList<String> resources)
	{
		File tmp;
		for (String st:resources)
		{
			Log.debug("Replacing resource: "+st+" At file: "+getAbsolutePath());
			if (!isCompiled())
			{
				Log.debug("file is not compiled");
				return false;
			}
			if (!extract(st,true))
			{
				Log.error("could not extract "+st+" from file "+getAbsolutePath());
				return false;
			}
			if (!compress(st,true))
			{
				Log.error("could not compress "+st+" to file "+getAbsolutePath());
				return false;
			}
			tmp=new File(st);
			tmp.delete();
		}
		return true;
	}
}
